#ifdef USE_HOOKS

/* 

Autor: Mountaniol Vsevolod. 
File: this file implements a mechanism of hooks.
Hooks are: 

upd_hook_begin();
upd_hook_output_open();
upd_hook_output_close();
upd_hook_buffer_read();
upd_hook_buffer_write();
upd_hook_encode();
upd_hook_decode();
upd_hook_compress();
upd_hook_decompress();
upd_hook_end();


Hook function is an external function placed in modules (shared librares).
The idea is that third party can easly add its own compressor, encryptors and so on.
So same core will work fine with every package, when part of packages may 
work only with apropriate modules (for example, proprietary encrypted).
Also I plan to develop ability to provide a module just inside of package:
in such situation updater first extract the modile, load it, and with help of the new module 
it unpack the rest of package.

*/
#if 0
#include <string.h>
#endif

#include "updater.types.h"
#include "updater.hooks.h"
#include "updater.w.h"
#include "updater.w.memory.h"
#include "updater.errors.h"
uhooks_t uhooks;


/* Hooks realisation. */
/* hookchain_t it is a node in linked list.*/
/* Every such node keeps pointer to function - a node, priority and pointer to next. */
static hookchain_t * hookchain_begin;
static hookchain_t * hookchain_buffer_in;
static hookchain_t * hookchain_buffer_out ;
static hookchain_t * hookchain_checksum;
static hookchain_t * hookchain_compress;
static hookchain_t * hookchain_decode;
static hookchain_t * hookchain_decompress;
static hookchain_t * hookchain_encode;
static hookchain_t * hookchain_end;
static hookchain_t * hookchain_in_file_opened;
static hookchain_t * hookchain_out_file_opened;
static hookchain_t * hookchain_spec_read;



/* Afrer every hook action like encription etc., I need to copy content of OUT buffer */
/* to IN buffer before passing it to a next hook */
/* So I do zero copy - just cross pointers to buffers */

static INT CrossIOBuffers(ucore_t * ps_ucore)
{
    VOID * pv_tmp;

    /* Cross the buffers */
    pv_tmp = ps_ucore->buffers.buffer_in;
    ps_ucore->buffers.buffer_in = ps_ucore->buffers.buffer_out;
    ps_ucore->buffers.buffer_out = pv_tmp;

    /* Cross the sizes */
    pv_tmp = ps_ucore->buffers.size_in;
    ps_ucore->buffers.size_in = ps_ucore->buffers.size_out;
    ps_ucore->buffers.size_out = ps_ucore->buffers.size_in;

    RETURN(OK);
}


/* It is a generic function that does the work. Every other hook fuction just call this one */

static INT hook_generic (VOID * vs_ucore, INT i_additional, hookchain_t * hookch)
{
    INT i_rv;
    hookchain_t * ph = hookch;
    ENTRY();
    if (NULL == vs_ucore)
    {
        RETURN( - EARGUMENT );
    }

    while ( NULL != ph)
    {
        i_rv = ph->h(vs_ucore);
        if (i_rv & HOOK_CROSS)
        {
            CrossIOBuffers(vs_ucore);
        }

        if (i_rv & HOOK_STOP)
        {
            RETURN( i_rv );

        }
    }
    /* 

    After the hook processing cross the buffers:
    Output buffer now contains processed data
    and going to be input for next action 

    */

    

    RETURN(OK);
}



static INT hook_begin (VOID * vs_ucore, INT i_additional)
{
   INT i_rv;
   ENTRY();
   i_rv = hook_generic(vs_ucore,i_additional,hookchain_begin);
   RETURN(i_rv);
}

static INT hook_spec_read (VOID * vs_ucore, INT i_additional)
{
   INT i_rv;
   ENTRY();
   i_rv = hook_generic(vs_ucore,i_additional,hookchain_spec_read);
   RETURN(i_rv);
}


static INT hook_in_file_opened (VOID * vs_ucore, INT i_additional)
{
    INT i_rv;
    ENTRY();
    i_rv = hook_generic(vs_ucore,i_additional,hookchain_in_file_opened);
    RETURN(i_rv);
}


static INT hook_out_file_opened (VOID * vs_ucore, INT i_additional)
{
    INT i_rv;
    ENTRY();
    i_rv = hook_generic(vs_ucore,i_additional,hookchain_out_file_opened);
    RETURN(i_rv);
}


static INT hook_buffer_in (VOID * vs_ucore, INT i_additional)
{
    INT i_rv;
    ENTRY();
    i_rv = hook_generic(vs_ucore,i_additional,hookchain_buffer_in);
    RETURN(i_rv);
}

static INT hook_buffer_out (VOID * vs_ucore, INT i_additional)
{
    INT i_rv;
    ENTRY();
    i_rv = hook_generic(vs_ucore,i_additional,hookchain_buffer_out);
    RETURN(i_rv);
}

static INT hook_encode (VOID * vs_ucore, INT i_additional)
{
    INT i_rv;
    ENTRY();
    i_rv = hook_generic(vs_ucore,i_additional,hookchain_encode);
    RETURN(i_rv);
}

static INT hook_comperess (VOID * vs_ucore, INT i_additional)
{
    INT i_rv;
    ENTRY();
    i_rv = hook_generic(vs_ucore,i_additional,hookchain_decode);
    RETURN(i_rv);
}

static INT hook_decomperess (VOID * vs_ucore, INT i_additional)
{
    INT i_rv;
    ENTRY();
    i_rv = hook_generic(vs_ucore,i_additional,hookchain_decompress);
    RETURN(i_rv);
}

static INT hook_decode (VOID * vs_ucore, INT i_additional)
{
    INT i_rv;
    ENTRY();
    i_rv = hook_generic(vs_ucore,i_additional,hookchain_decode);
    RETURN(i_rv);
}

static INT hook_checksum (VOID * vs_ucore, INT i_additional)
{
    INT i_rv;
    ENTRY();
    i_rv = hook_generic(vs_ucore,i_additional,hookchain_checksum);
    RETURN(i_rv);
}

static INT hook_end (VOID * vs_ucore, INT i_additional)
{
    INT i_rv;
    ENTRY();
    i_rv = hook_generic(vs_ucore,i_additional,hookchain_end);
    RETURN(i_rv);
}



/* 
	FUNCTION: InitHooks 
	IN: ucore_t core
	OUT: status of operation: OK on success, < 0 on error.
	DESCRIPTION: Search and load external hhoks, if any. 

*/


INT LoadHooks(ucore_t * ps_ucore)
{

    RETURN(OK);
}




/* 
	FUNCTION: InitHooks 
	IN: void
	OUT: status of operation: OK on success, < 0 on error.
	DESCRIPTION: updater's hooks initialization. 

*/

INT InitHooks(ucore_t * ps_ucore)
{
	ENTRY();

/* Hooks realisation. */
    hookchain_begin = NULL;
    hookchain_buffer_in = NULL;
    hookchain_buffer_out = NULL;
    hookchain_checksum = NULL;
    hookchain_compress = NULL;
    hookchain_decode = NULL;
    hookchain_decompress = NULL;
    hookchain_encode = NULL;
    hookchain_end = NULL;
    hookchain_in_file_opened = NULL;
    hookchain_out_file_opened = NULL;
    hookchain_spec_read = NULL;

    w_memset(&ps_ucore->hooks, 0, sizeof(uhooks_t) );

    ps_ucore->hooks.hook_begin = hook_begin;
    ps_ucore->hooks.hook_buffer_in = hook_buffer_in;
    ps_ucore->hooks.hook_buffer_out = hook_buffer_out;
    ps_ucore->hooks.hook_checksum = hook_checksum;
    ps_ucore->hooks.hook_compress = hook_comperess;
    ps_ucore->hooks.hook_decode = hook_decode;
    ps_ucore->hooks.hook_decompress = hook_decomperess;
    ps_ucore->hooks.hook_encode = hook_encode;
    ps_ucore->hooks.hook_end = hook_end;
    ps_ucore->hooks.hook_in_file_opened = hook_in_file_opened;
    ps_ucore->hooks.hook_out_file_opened = hook_out_file_opened;
    ps_ucore->hooks.hook_spec_read = hook_spec_read;
    
	RETURN( 0 );
}



#else
#warning No hooks.
#endif /* USE_HOOKS */


